Gleam: Basics
from Gleam Launguage Tour
Modules
Gleam では、すべてのコードは モジュール に属する
e.g. gleam/io
あるモジュールから別のモジュールのコードにアクセスするには、import を用いる
code:gleam
import gleam/io
import gleam/string as text
pub fn main() {
io.println("Hello, Mike!")
}
as を用いると、別名でアクセスできる
code:gleam
import gleam/io
import gleam/string as text
pub fn main() {
io.println(text.reverse("Hello, Joe!"))
}
Unqualified imports
warning.icon 関数が定義されている場所が不明確になり 可読性 が落ちるので、あまり使わないこと
import 時に . を用いることで、モジュール名を付けず(修飾せず)にコードにアクセスできる
code:gleam
import gleam/io.{println}
pub fn main() {
io.println("This is qualified")
println("This is unqualified")
}
Type checking
Gleam は強力な 型システム を持つ
null も 暗黙の型変換 もなく、常に完全な型チェックを行う
e.g.
gleam/io.println のシグネチャは pub fn println(string: String) -> Nil
文字列以外を渡すコンパイルエラーを引き起こす
code:gleam
import gleam/io
pub fn main() {
io.println("My lucky number is:")
io.println(4)
}
code:text
error: Type mismatch
┌─ /src/main.gleam:5:14
│
5 │ io.println(4)
│ ^
Expected type:
String
Found type:
Int
回避策
gleam/io.debug を用いる
pub fn debug(term: a) -> a
code:fsharp
pub fn main() {
io.println("My lucky number is:")
io.debug(4)
}
Ints
Int 型は整数を表す
BEAM 上で実行する場合、最大・最小値は無い
JS runtime 上で実行する場合、64 bit 浮動小数点数として表現される
code:gleam
import gleam/io
pub fn main() {
io.debug(1 + 1) // 2
io.debug(5 - 1) // 4
io.debug(5 / 2) // 2
io.debug(3 * 3) // 9
io.debug(5 % 2) // 1
io.debug(2 > 1) // True
io.debug(2 < 1) // False
io.debug(2 >= 1) // False
io.debug(2 <= 1) // True
io.debug(1 == 1) // True
io.debug(2 == 1) // False
}
整数を操作する標準ライブラリモジュールとして、gleam/int が提供されている
https://hexdocs.pm/gleam_stdlib/gleam/int.html
code:gleam
import gleam/int
import gleam/io
pub fn main() {
io.debug(int.max(42, 77)) // 77
io.debug(int.clamp(5, 10, 20)) // 10
}
Floats
Float 型は浮動小数点数を表す
Erlang と JavaScript 両方のランタイムで 64 bit 浮動小数点数として表現される
しかし、動作はそれぞれのランタイムに固有なので、正確な動作は少し異なる
JavaScript
表現可能な最大値(最小値)を超えると、Infinity(-Infinity)と表現される
Infinity 同士を除算すると NaN になる
Erlang
オーバーフロー するとエラーになる
0 による除算はオーバーフローせず 0 と定義される
Int も一緒
io.debug(3.14 /. 0.0) // 0
演算子は オーバーロード されていないので、専用の演算子を提供している
code:gleam
io.debug(1.0 +. 1.5)
io.debug(5.0 -. 1.5)
io.debug(5.0 /. 2.5)
io.debug(3.0 *. 3.5)
io.debug(2.2 >. 1.3)
io.debug(2.2 <. 1.3)
io.debug(2.2 >=. 1.3)
io.debug(2.2 <=. 1.3)
浮動小数点数を操作する標準ライブラリモジュールとして、gleam/float が提供されている
https://hexdocs.pm/gleam_stdlib/gleam/float.html
code:gleam
import gleam/float
import gleam/io
pub fn main() {
io.debug(float.max(2.0, 9.5)) // 9.5
io.debug(float.ceiling(5.4)) // 6
}
Number formats
可読性 を上げるため、1_000_000 のように 数値に _ を付けることが可能
2 進数、8 進数、16 進数を記述したい場合は、接頭辞として 0b や 0o、0x を付けることで実現できる
code:gleam
0b00001111 // 15
0o17 // 15
0xF // 15
e を用いて 10 の冪乗を表現できる
code:fsharp
7.0e7
3.0e-4
Equality
等価性 をチェックする演算子として == と != を提供している
演算子の 両側は同じ型 である必要がある
等価性は 構造的 にチェックされる
2 つの値が同じメモリ位置にあるかどうかではなく、同じ構造を持っている場合に等しくなる
code:fsharp
100 == 100 // True
1.5 != 0,1 // True
Strings
Gleam では文字列を " で囲む
"Hello, Gleam!"
型は String
複数行にまたがり、ユニコード文字を含むこともできる
"👩‍💻 こんにちは Gleam 🏳️‍🌈"
文字列を連結するには <> 演算子が使える
"One " <> "Two"
エスケープ文字 もサポート
\": ダブルクォート
\\: バックスラッシュ
\f: 改ページ
\n: 改行
\r: キャリッジリターン(復帰改行)
\t: タブ
\u{xxxxxx}: コードポイント
文字列を操作する標準ライブラリモジュールとして、gleam/string が提供されている
https://hexdocs.pm/gleam_stdlib/gleam/string.html
code:gleam
import gleam/string
pub fn main() {
io.debug(string.reverse("1 2 3")) // "3 2 1"
io.debug(string.append("abc", "def")) // "abcdef"
}
Bools
真偽値は True か False
型は Bool
他の多くの言語と同様に、論理演算子は 短絡評価
真偽値を操作する標準ライブラリモジュールとして、gleam/bool が提供されている
https://hexdocs.pm/gleam_stdlib/gleam/bool.html
code:gleam
import gleam/bool
pub fn main() {
bool.to_string(True) // "True"
bool.to_int(False) // 0
}
Assignments
値は let で変数に 束縛 できる
Gleam では、変数・関数名に sneak_case を用いる
code:gleam
let x_str = "Original"
io.println(x_str) // "Original"
別の値で再束縛することはできるが、参照する値は イミュータブル であるため、値自体が変更されたりすることはない
code:gleam
let y_str = x_str
io.debug(y_str) // "Original"
let x_str = "New"
io.println(x_str) // "New"
io.debug(y_str) // "Original"
Discard patterns
コンパイラは未使用の変数を見つけると、警告を表示する
let score = 1000
code:text
warning: Unused variable
┌─ /src/main.gleam:3:7
│
3 │ let score = 1000
│ ^^^^^ This variable is never used
Hint: You can ignore it with an underscore: _score.
接頭辞として _ を付けると、この警告を無視できる
let _score = 1000
Type annotations
変数に 型注釈 を付けることが可能
ただし、型推論 が極力なので一般的ではない
主な用途はドキュメント
let _name: String = "Gream"
異なる型の値を束縛しようとすると、コンパイルエラーが起きる
let _name: Int = "Gleam"
code:text
error: Type mismatch
┌─ /src/main.gleam:2:20
│
2 │ let _name: Int = "Gleam"
│ ^^^^^^^
Expected type:
Int
Found type:
String
Type imports
関数と同じように、他のモジュールで定義されている型も import 可能
Gleam: Basics#66ab18c975d04f0000ff4b63
code:gleam
import gleam/bytes_builder
pub fn main() {
let _bytes: bytes_builder.BytesBuilder = bytes_builder.new()
}
. と type を用いることで他のモジュールで定義されている型に直接アクセスできる
warning.icon 関数とは異なり、型の場合はこちらが推奨
Gleam: Basics#66ab19ae75d04f0000ff4b81
code:gleam
import gleam/string_builder.{type StringBuilder}
pub fn main() {
let _text: StringBuilder = string_builder.new()
}
Type aliases
型エイリアス には type を用いる
code:gleam
pub type UserId = Int
新しい型ができるわけではなく、同じ型である
code:gleam
let one: UserId = 1
let two: Int = 2
io.debug(one == two) // False
let two = 1
io.debug(one == two) // True
pub を付けると、他のモジュールからアクセス可能になる
型名は UpperCamelCase で記述する
Blocks
{ でグルーピングされた 1 つ以上の式を「ブロック」と呼ぶ
格式は順番に評価され、最後の式の値が返される
Rust と一緒
e.g.
code:gleam
let fahrenheit = {
let degrees = 64
degrees
}
ブロック内で割り当てられた変数は、ブロック内のみで利用できる
code:gleam
let fahrenheit = {
let degrees = 64
degrees
}
io.debug(degree) // コンパイルエラー
二項演算子の評価順序を変えるために用いられる
他の言語の ( の代わりっぽい radish-miyazaki.icon
code:gleam
let celsius = { fahrenheit - 32 } * 5 / 5
io.debug(celsius) // 17
Lists
順序付けられた値の集合
[1, 2, 3]
より厳密には、イミュータブル な 単連結リスト
https://algo-logic.info/wp-content/uploads/2019/11/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2019-11-25-15.04.46-1024x718.png
そのため、先頭要素を追加・削除するのが効率的である
一方、長さを数えたり、任意の位置から要素を取得するのはコストが高い
前者の場合は Iterator 、後者の場合は Dict など、他の型を使ったほうが良い
https://hexdocs.pm/gleam_stdlib/gleam/iterator.html
https://hexdocs.pm/gleam_stdlib/gleam/dict.html
ジェネリック型
要素が整数: List(Int)
要素が文字列: List(String)
.. で展開できる
code:gleam
let ints = 1, 2, 3
io.debug(-1, 0, ..ints) // -1, 0, 1, 2, 3
io.debug(ints) // 1, 2, 3
Constants
定数 は、const を用いてモジュールの最上位で定義する
code:gleam
const ints: List(Int) = 1, 2, 3
const floats = 1.0, 2.0, 3.0
リテラル値である必要がある
関数は不可
複数の関数で同じ値を作成するよりも効率的になる可能性がある
ランタイムや Erlang にコンパイルするか、JavaScript にコンパイルするかで異なる
#Gleam